package com.fabiodocarmo.calendario.dao.util;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;

/**
 * Classe responsável por construir a fábrica de sessões.
 *
 * @author Taciano Morais Silva
 * @version 12/02/2009, 11h28m
 * @since 15/10/2008, 12h00m
 */
public class HibernateFactory {

    /**
     * Logger da Classe.
     */
    private static Logger logger = Logger.getLogger(HibernateFactory.class);

    /**
     * Fábrica de sessões.
     */
    private static SessionFactory sessionFactory;

    /**
     * Constructs a new Singleton SessionFactory.
     * @return A fábrica de sessão.
     * @throws HibernateException Caso ocorra erro na configuração e construção
     * da fábrica de sessões.
     */
    public static SessionFactory buildSessionFactory()
            throws HibernateException {
        // TODO não parece um singleton, rever esta implementação.
        if (sessionFactory != null) {
            closeFactory();
        }
        return configureSessionFactory();
    }

    /**
     * Constrói uma SessionFactory, se ela ainda for nula.
     * @return A fábrica de sessão do hibernate.
     * @throws HibernateException Caso ocorra erro na configuração e construção
     * da fábrica de sessões.
     */
    public static SessionFactory buildIfNeeded() throws HibernateException {
        if (sessionFactory != null) {
            return sessionFactory;
        }
        try {
            return configureSessionFactory();
        } catch (HibernateException e) {
            throw e;
        }
    }

    /**
     * Carrega as configurações nas anotações e constrói a fábrica de sessão.
     * @return A fábrica de sessão.
     * @throws HibernateException Caso ocorra erro na configuração e construção
     * da fábrica de sessões.
     */
    private static SessionFactory configureSessionFactory()
            throws HibernateException {
        AnnotationConfiguration configuration = new AnnotationConfiguration();
        configuration.configure();
        sessionFactory = configuration.buildSessionFactory();
        return sessionFactory;
    }

    /**
     * Retorna a fábrica de sessão iniciada.
     * @return A instância da fábrica de sessão.
     */
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    /**
     * Abre uma nova sessão. Caso a fábrica ainda não tenha sido iniciada
     * é feita uma chamada ao método {@link HibernateFactory#buildIfNeeded()}.
     * @return Uma nova sessão.
     * @throws HibernateException Caso ocorra uma exceção na construção da
     * fábrica de sessões ou na abertura da nova sessão.
     */
    public static Session openSession() throws HibernateException {
        buildIfNeeded();
        return sessionFactory.openSession();
    }

    /**
     * Fecha a fábrica de sessões, caso o fechamento gere exceção é feito um
     * log de ERROR.
     */
    public static void closeFactory() {
        if (sessionFactory != null) {
            try {
                sessionFactory.close();
            } catch (HibernateException ignored) {
                logger.error("Couldn't close SessionFactory", ignored);
            }
        }
    }

    /**
     * Fecha a sessão, caso a sessão esteja fechada acrescenta no log um WARN.
     * @param session Uma sessão hibernate.
     */
    public static void close(Session session) {
        if (session != null) {
            try {
                session.close();
            } catch (HibernateException ignored) {
                logger.warn("Couldn't close Session");
            }
        }
    }

    /**
     * Executa o rollback da transação.
     * @param tx A transação.
     */
    public static void rollback(Transaction tx) {
        try {
            if (tx != null) {
                tx.rollback();
            }
        } catch (HibernateException ignored) {
            logger.error("Couldn't rollback Transaction", ignored);
        }
    }
}

